home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / modules / nessus-2.2.8.mo / usr / lib / nessus / plugins / ssl_funcs.inc < prev    next >
Text File  |  2005-03-31  |  20KB  |  565 lines

  1. # (C) 2003 Tenable Network Security
  2. # $Id
  3.  
  4.  
  5. # This function generates an SSL / TLS Client Hello message. For specs, see:
  6. #   - http://wp.netscape.com/eng/security/SSL_2.html (SSLv2)
  7. #   - http://wp.netscape.com/eng/ssl3/draft302.txt (SSLv3)
  8. #   - http://www.ietf.org/rfc/rfc2246.txt (TLSv1)
  9. #
  10. # Args:
  11. #   o mlen = message length after this byte; 1 byte.
  12. #   o mtype = handshake message type; 1 byte.
  13. #     nb: 0x01 => Client Hello (default).
  14. #   o version = client SSL version; 2 bytes.
  15. #     nb: 0x0002 => SSLv2, 0x0300 => SSLv3 (default), 0x0301 => TLSv1.
  16. #   o v2hello = whether to use v2 client hello format.
  17. #     nb: FALSE (use protocol-specific format), TRUE (default).
  18. #   o cipherspec = which ciphers are supported.
  19. #   o cspeclen = cipher spec len; 2 bytes.
  20. #   o sessionid = session ID (defaults to empty string
  21. #     or random bytes if sessionidlen is non-zero).
  22. #   o sessionidlen = session ID length; 2 bytes for SSLv2, 1 byte otherwise.
  23. #   o challenge = random bytes of challenge data.
  24. #     nb: for SSLv2, defaults to "NESSUSNESSUSNESS";
  25. #         for SSLv3 or TLSv1, defaults to current unix datetime
  26. #         followed by "NESSUSNESSUSNESSUSNESSUSNESS".
  27. #   o challengelen = length of challenge; 2 bytes.
  28. #     nb: this is used only with SSLv2 format hellos.
  29. #   o compmeths = list of compression methods supported by client,
  30. #     1 byte each (defaults to 0x00 => no compression).
  31. #     nb: this is not used with SSLv2.
  32. #   o compmethslen = length of compression methods.
  33. # Return:
  34. #   o a raw string representing the Client Hello message.
  35. #
  36. # updated: 16-Nov-2004, George A. Theall
  37. #
  38. # updated: 29-Dec-2004, Tenable Network Security / jwl
  39.  
  40.  
  41. function client_hello(mlen, mtype, version, v2hello, cipherspec, cspeclen, sessionid, sessionidlen, challenge, challengelen, compmeths, compmethslen) {
  42.   local_var chello, chellolen, handshake, myhello;
  43.  
  44.   # Assign some defaults.
  45.   if ( (mtype <= 0) || isnull(version) ) mtype = raw_string(0x01);            # set to hello packet by default
  46.   if (isnull(version)) version = raw_string(0x03, 0x00);
  47.   if (isnull(v2hello)) v2hello = TRUE;
  48.  
  49.   # Generate the hello.
  50.   #
  51.   # - SSLv2, whether it's explicitly SSLv2 or in v2 compatability mode.
  52.   if (version == raw_string(0x00, 0x02) || v2hello == TRUE) {
  53.     # Assign other defaults.
  54.     #
  55.     # - ciphers.
  56.     if (isnull(cipherspec)) {
  57.       if ( (isnull(cspeclen)) || (cspeclen <= 0 ) ) 
  58.         cipherspec = 
  59.           # TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA
  60.           raw_string(0x00, 0x00, 0x62) +
  61.           # SSL2_RC2_CBC128_CBC_WITH_MD5
  62.           raw_string(0x04, 0x00, 0x80) +
  63.           # TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA
  64.           raw_string(0x00, 0x00, 0x63) +
  65.           # TLS_RSA_EXPORT_WITH_RC4_40_MD5
  66.           raw_string(0x00, 0x00, 0x03) +
  67.           # TLS_RSA_EXPORT1024_WITH_RC4_56_SHA
  68.           raw_string(0x00, 0x00, 0x64) +
  69.           # SSL2_RC4_128_EXPORT40_WITH_MD5
  70.           raw_string(0x02, 0x00, 0x80);
  71.       else 
  72.         # nb: fill it with random bytes.
  73.         while (strlen(cipherspec) < cspeclen)
  74.           cipherspec = cipherspec + (rand() % 256);
  75.     }
  76.     if (isnull(cspeclen)) {
  77.       cspeclen = strlen(cipherspec); 
  78.       cspeclen = raw_string(cspeclen / 256, cspeclen % 256);
  79.     }
  80.     # - session ID.
  81.     if (isnull(sessionid)) {
  82.       if (sessionidlen) 
  83.         # nb: fill it with random bytes.
  84.         while (strlen(sessionid) < sessionidlen)
  85.           sessionid = sessionid + (rand() % 256);
  86.       else sessionid = "";
  87.     }
  88.     if (isnull(sessionidlen)) {
  89.       sessionidlen = strlen(sessionid);
  90.       sessionidlen = raw_string(sessionidlen / 256, sessionidlen % 256);
  91.     }
  92.     # - challenge.
  93.     if (isnull(challenge)) challenge = "NESSUSNESSUSNESS";
  94.     if (isnull(challengelen)) {
  95.       challengelen = strlen(challenge);
  96.       challengelen = raw_string(challengelen / 256, challengelen % 256);
  97.     }
  98.  
  99.     # Assemble the message.
  100.     # nb: 2 byte length code is used since we don't need any padding.
  101.     handshake = mtype +
  102.                 version +
  103.                 cspeclen +
  104.                 sessionidlen +
  105.                 challengelen +
  106.                 cipherspec;
  107.     if (sessionid) handshake = handshake + sessionid;
  108.     handshake = handshake + challenge;
  109.     if ( (mlen <= 0) || isnull(mlen) ) mlen = strlen(handshake);
  110.     myhello = raw_string(0x80 | (mlen / 256), mlen % 256) + handshake;
  111.   }
  112.   # - SSLv3 or TLSv1.
  113.   else if (version == raw_string(0x03, 0x00) || version == raw_string(0x03, 0x01)) {
  114.     # Assign other defaults.
  115.     #
  116.     # - ciphers.
  117.     if (isnull(cipherspec)) {
  118.       if (isnull(cspeclen)) 
  119.         # nb: this is what openssl s_client uses by default.
  120.         cipherspec = 
  121.           # TLS_DHE_RSA_WITH_AES_256_CBC_SHA
  122.           raw_string(0x00, 0x39) +
  123.           # TLS_DHE_DSS_WITH_AES_256_CBC_SHA
  124.           raw_string(0x00, 0x38) +
  125.           # TLS_RSA_WITH_AES_256_CBC_SHA
  126.           raw_string(0x00, 0x35) +
  127.           # TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
  128.           raw_string(0x00, 0x16) +
  129.           # TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
  130.           raw_string(0x00, 0x13) +
  131.           # TLS_RSA_WITH_3DES_EDE_CBC_SHA
  132.           raw_string(0x00, 0x0a) +
  133.           # TLS_DHE_RSA_WITH_AES_128_CBC_SHA
  134.           raw_string(0x00, 0x33) +
  135.           # TLS_DHE_DSS_WITH_AES_128_CBC_SHA
  136.           raw_string(0x00, 0x32) +
  137.           # TLS_RSA_WITH_AES_128_CBC_SHA
  138.           raw_string(0x00, 0x2f) +
  139.           # TLS_RSA_WITH_IDEA_CBC_SHA
  140.           raw_string(0x00, 0x07) +
  141.           # TLS_DHE_DSS_WITH_RC4_128_SHA
  142.           raw_string(0x00, 0x66) +
  143.           # TLS_RSA_WITH_RC4_128_SHA
  144.           raw_string(0x00, 0x05) +
  145.           # TLS_RSA_WITH_RC4_128_MD5
  146.           raw_string(0x00, 0x04) +
  147.           # TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA
  148.           raw_string(0x00, 0x63) +
  149.           # TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA
  150.           raw_string(0x00, 0x62) +
  151.           # TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5
  152.           raw_string(0x00, 0x61) +
  153.           # TLS_DHE_RSA_WITH_DES_CBC_SHA
  154.           raw_string(0x00, 0x15) +
  155.           # TLS_DHE_DSS_WITH_DES_CBC_SHA
  156.           raw_string(0x00, 0x12) +
  157.           # TLS_RSA_WITH_DES_CBC_SHA
  158.           raw_string(0x00, 0x09) +
  159.           # TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA
  160.           raw_string(0x00, 0x65) +
  161.           # TLS_RSA_EXPORT1024_WITH_RC4_56_SHA
  162.           raw_string(0x00, 0x64) +
  163.           # TLS_RSA_EXPORT1024_WITH_RC4_56_MD5
  164.           raw_string(0x00, 0x60) +
  165.           # TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
  166.           raw_string(0x00, 0x14) +
  167.           # TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
  168.           raw_string(0x00, 0x11) +
  169.           # TLS_RSA_EXPORT_WITH_DES40_CBC_SHA
  170.           raw_string(0x00, 0x08) +
  171.           # TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
  172.           raw_string(0x00, 0x06) +
  173.           # TLS_RSA_EXPORT_WITH_RC4_40_MD5
  174.           raw_string(0x00, 0x03);
  175.       else 
  176.         # nb: fill it with random bytes.
  177.         while (strlen(cipherspec) < cspeclen)
  178.           cipherspec = cipherspec + (rand() % 256);
  179.     }
  180.     if (isnull(cspeclen)) {
  181.       cspeclen = strlen(cipherspec);
  182.       cspeclen = raw_string(cspeclen / 256, cspeclen % 256);
  183.     }
  184.     # - session ID.
  185.     if (isnull(sessionid)) {
  186.       if (sessionidlen) {
  187.         # nb: fill out field with random bytes.
  188.         while (strlen(sessionid) < sessionidlen)
  189.           sessionid = sessionid + (rand() % 256);
  190.       }
  191.       else sessionid = "";
  192.     }
  193.     if (isnull(sessionidlen)) sessionidlen = raw_string(strlen(sessionid));
  194.     # - challenge.
  195.     if (isnull(challenge)) {
  196.       challenge = dec2hex(num:unixtime()) + "NESSUSNESSUSNESSUSNESSUSNESS";
  197.     }
  198.     # - compression methods
  199.     if (isnull(compmeths)) {
  200.       compmeths = raw_string(0x00);
  201.       # nb: fill out field with random bytes.
  202.       while (strlen(compmeths) < compmethslen)
  203.         compmeths = compmeths + (rand() % 256);
  204.     }
  205.     if (isnull(compmethslen)) compmethslen = raw_string(strlen(compmeths));
  206.  
  207.     # Assemble the message.
  208.     chello = version +
  209.              challenge + 
  210.              sessionidlen + sessionid +
  211.              cspeclen + cipherspec +
  212.              compmethslen + compmeths;
  213.     chellolen = strlen(chello);
  214.     handshake = mtype +
  215.               raw_string(0, chellolen / 256, chellolen % 256) +
  216.               chello;
  217.     if (isnull(mlen)) mlen = strlen(handshake);
  218.     myhello = raw_string(0x16) +
  219.               version +
  220.               raw_string(mlen / 256, mlen % 256) +
  221.               handshake;
  222.   }
  223.  
  224.   return(myhello);
  225. }
  226.  
  227.  
  228. function client_send_cert (contenttype, version, length, hshaketype, hlength, clength, clength2, certificate) {
  229.   # contenttype = content type (1 byte) -- handshake is 0x16
  230.   # version = version (2 bytes) -- SSL v3 is 0x03 0x00
  231.   # length = length (2 bytes) of record following this length field
  232.   # hshaketype = handshake type (1 byte) -- certificate is 0x0B
  233.   
  234.   # Note to self:  3 bytes is a *lot* of space...
  235.  
  236.   # hlength = handshake length (3 bytes) (also equal to length - 4)
  237.   # clength = certificate length (3 bytes) (or hlength - 3)
  238.   # clength2 = actual cert length (3 bytes) (just subtract another 3 from clength)
  239.   # certificate = clength2 bytes of certificate
  240.   
  241.  
  242.   if (!certificate) exit(0);                      # must have a cert... 
  243.  
  244.   certlen = strlen(certificate);
  245.  
  246.   if (!contenttype) contenttype = raw_string(0x16);
  247.   if (!version) version = raw_string(0x03, 0x00);
  248.   if (!hshaketype) hshaketype = raw_string(0x0B);
  249.  
  250.   if (!clength2) {
  251.     clength2 = certlen; 
  252.     if (clength2 <= 0xFF) clength2 = raw_string(0x00, 0x00, clength2);
  253.     else clength2 = raw_string(0x00, clength2 / 256, clength2 % 256); 
  254.   }
  255.  
  256.   if (!clength) {
  257.       tlen = certlen + 3;
  258.       if (tlen <= 0xFF) clength = raw_string(0x00, 0x00, tlen);
  259.       else clength = raw_string(0x00, tlen / 256, tlen % 256); 
  260.   }
  261.  
  262.   if (!hlength) {
  263.       tlen = certlen + 6;
  264.       if (certlen <= 0xFF) hlength = raw_string(0x00, 0x00, tlen);
  265.       else hlength = raw_string(0x00, tlen / 256, tlen % 256);
  266.   }
  267.  
  268.   if (!length) {
  269.     length = certlen + 10;
  270.     if (length <= 0xFF) length = raw_string(0x00, strlen(length));
  271.     else length = raw_string(length / 256, length % 256);
  272.   }
  273.  
  274.  
  275.     
  276.   client_cert = contenttype + version + length + hshaketype + hlength + clength + clength2 + certificate;
  277.   return (client_cert); 
  278. }
  279.  
  280.  
  281. # This function returns the message digest (fingerprint) of a string.
  282. #
  283. # Args:
  284. #   o string - the string to fingerprint.
  285. #   o type - the type of message digest to use, either MD5 (default) or SHA1.
  286. #
  287. # Return:
  288. #   o a string of hex numbers, each separated by a colon, representing 
  289. #     the string's fingerprint.
  290. #
  291. # updated: 16-Nov-2004, George A. Theall
  292. #
  293. function fingerprint_string(str, type) {
  294.   local_var digest;
  295.  
  296.   if (isnull(str)) return(NULL);
  297.   if (isnull(type)) type = "md5";
  298.  
  299.   if (type =~ "md5") {
  300.     digest = MD5(str);
  301.   }
  302.   else if (type =~ "sha1") {
  303.     digest = SHA1(str);
  304.   }
  305.   else {
  306.     # unsupported digest type.
  307.     return(NULL);
  308.   }
  309.  
  310.   digest = ereg_replace(string:hexstr(digest), pattern:"(..)", replace:"\1:");
  311.   digest = substr(digest, 0, strlen(digest)-2);
  312.  
  313.   return(digest);
  314. }
  315.  
  316.  
  317. # This function returns the message digest (fingerprint) of an SSL 
  318. # certificate.
  319. #
  320. # Args:
  321. #   o cert - the certificate (either PEM or DER-encoded).
  322. #   o type - the type of digest to use, either MD5 (default) or SHA1.
  323. #
  324. # Return:
  325. #   o a string of hex numbers, each separated by a colon, representing 
  326. #     the certificate's fingerprint.
  327. #
  328. # updated: 16-Nov-2004, George A. Theall
  329. #
  330. function fingerprint_cert(cert, type) {
  331.   local_var der;
  332.  
  333.   if (isnull(type)) type = "md5";
  334.  
  335.   # If the cert is PEM-encoded, convert it to DER-encoding.
  336.   if (egrep(string:cert, pattern:"(BEGIN CERTIFICATE|^.{64}$)")) {
  337.     der = "";
  338.     foreach line (split(cert, keep:TRUE)) {
  339.       if (line !~ "^-+(BEGIN|END) CERTIFICATE-+$") {
  340.         der += line;
  341.       }
  342.     }
  343.     cert = base64_decode(der);
  344.   }
  345.  
  346.   return(fingerprint_string(str:cert, type:type));
  347. }
  348.  
  349.  
  350. # This function returns the server certificate for the SSL-enabled
  351. # service on a given port.
  352. #
  353. # Args:
  354. #   o port - a port number.
  355. #   o encoding - format of certificate, either PEM (default) or DER.
  356. #
  357. # Return:
  358. #   o a string representing the SSL certificate.
  359. #
  360. # updated: 16-Nov-2004, George A. Theall
  361. #
  362. function get_server_cert(port, encoding) {
  363.   local_var cert;
  364.  
  365.   if (isnull(port)) return(NULL);
  366.   if (isnull(encoding)) encoding = "pem";
  367.  
  368.   # Try to get cert from the KB.
  369.   cert = get_kb_item("SSL/Certificate/" + port);
  370.  
  371.   # If that didn't work, retrieve it directly.
  372.   if (!cert) {
  373.     local_var buf, hello, done, encaps, hexmsg, host, soc, ssl;
  374.     local_var msg, msg_len, msg_type;
  375.     local_var hand, hand_len, hand_type;
  376.     local_var cert, cert_len;
  377.     local_var alert_desc, alert_lvl, err_code;
  378.  
  379.     host = get_host_name();
  380.     if (!get_port_state(port)) return(NULL);
  381.     soc = open_sock_tcp(port, transport:ENCAPS_IP);
  382.     if (!soc) exit(0);
  383.  
  384.     encaps = get_kb_item("Transports/TCP/"+port);
  385.     
  386.     if (!encaps) return(NULL);
  387.     if (debug_level) display("debug: encapsulation type is ", encaps, ".\n");
  388.     # nb: see nessus-libraries/include/libnessus.h for defines
  389.     #     mapping encapsulations to SSL / TLS version.
  390.     if (encaps == 3) ssl = "SSLv2";
  391.     else if (encaps == 4) ssl = "SSLv3";
  392.     else if (encaps == 5) ssl = "TLSv1";
  393.     else return(NULL);
  394.     if (debug_level) display("debug: fingerprinting ", ssl, " certificate on ", host, ":", port, ".\n");
  395.  
  396.     # Send client hello.
  397.     if (ssl == 'SSLv2') {
  398.       hello = client_hello(version:raw_string(0x00, 0x02));
  399.     }
  400.     else if (ssl == 'SSLv3') {
  401.       hello = client_hello(v2hello:FALSE, version:raw_string(0x03, 0x00));
  402.     }
  403.     else if (ssl == 'TLSv1') {
  404.       hello = client_hello(v2hello:FALSE, version:raw_string(0x03, 0x01));
  405.     }
  406.     if (debug_level) {
  407.       display("debug: sending ", ssl, " Client Hello:\n");
  408.       hexmsg = ereg_replace(string:hexstr(hello), pattern:"(..)", replace:"0x\1 ");
  409.       if (!hexmsg) hexmsg = "-- empty --";
  410.       display("debug:   ", hexmsg, "\n");
  411.     }
  412.     send(socket:soc, data:hello);
  413.     buf = recv(socket:soc, length:8192); 
  414.     close(soc);
  415.  
  416.     # Process server message(s). 
  417.     done = 0;
  418.     if (ssl == 'SSLv2') {
  419.       # Isolate a message.
  420.       while (!done && strlen(buf) > 3) {
  421.         msg_type = ord(buf[2]);
  422.         msg_len = ((ord(buf[0]) & 0x7f) << 8) | ord(buf[1]);
  423.         msg = substr(buf, 0, msg_len+2-1);
  424.         if (debug_level) {
  425.           display("debug: message type: ", msg_type, ".\n");
  426.           display("debug:   length:     ", msg_len, ".\n");
  427.           hexmsg = ereg_replace(string:hexstr(msg), pattern:"(..)", replace:"0x\1 ");
  428.           if (!hexmsg) hexmsg = "-- empty --";
  429.           display("debug:   contents:   ", hexmsg, "\n");
  430.         }
  431.         buf = substr(buf, msg_len);
  432.  
  433.         # Handshake message.
  434.         if (msg_type == 4 && strlen(msg) > 14) {
  435.           # X.509 certificate.
  436.           if (ord(msg[4]) == 1) {
  437.             cert_len = ord(msg[7])*256 + ord(msg[8]);
  438.             cert = substr(msg, 13, cert_len+13-1);
  439.             if (debug_level) {
  440.               display("debug: cert length: ", cert_len, ".\n");
  441.               hexmsg = ereg_replace(string:hexstr(cert), pattern:"(..)", replace:"0x\1 ");
  442.               if (!hexmsg) hexmsg = "-- empty --";
  443.               display("debug:   contents:  ", hexmsg, "\n");
  444.             }
  445.             done = 1;
  446.           }
  447.         }
  448.         # Error message.
  449.         else if (msg_type == 0 && strlen(msg) == 2) {
  450.           err_code = ord(msg[1]) * 256 + ord(msg[1]);
  451.           if (debug_level) display("debug: error code: ", err_code, "\n");
  452.         }
  453.         # Something else.
  454.         else {
  455.           if (log_verbosity > 1) display("Message of type ", msg_type, " received from ", host, ":", port, "!\n");
  456.         }
  457.         if (debug_level) display("debug:\n");
  458.       }
  459.     }
  460.     else if (ssl == 'SSLv3' || ssl == 'TLSv1') {
  461.       # We *should* see the Server Hello handshake first, followed by the Server
  462.       # Certificate handshake, but not depending on the order is more robust.
  463.       while (!done && strlen(buf) > 5) {
  464.         msg_type = ord(buf[0]);
  465.         msg_len = ord(buf[3])*256 + ord(buf[4]);
  466.         # nb: msg_len doesn't include the first 5 bytes.
  467.         msg = substr(buf, 0, msg_len+5-1);
  468.         if (debug_level) {
  469.           display("debug: message type: ", msg_type, ".\n");
  470.           display("debug:   length:     ", msg_len, ".\n");
  471.           hexmsg = ereg_replace(string:hexstr(msg), pattern:"(..)", replace:"0x\1 ");
  472.           if (!hexmsg) hexmsg = "-- empty --";
  473.           display("debug:   contents:   ", hexmsg, "\n");
  474.         }
  475.         buf = substr(buf, msg_len+5);
  476.  
  477.         # Handshake message.
  478.         if (msg_type == 22 && strlen(msg) > 3) {
  479.           while (!done && strlen(msg) > 4) {
  480.             hand_type = ord(msg[5]);
  481.             hand_len = ord(msg[6])*65536 + ord(msg[7])*256 + ord(msg[8]);
  482.             # nb: hand_len doesn't include the first 4 bytes.
  483.             hand = substr(msg, 5, hand_len+4+5-1);
  484.             if (debug_level) {
  485.               display("debug: handshake type: ", hand_type, ".\n");
  486.               display("debug:   length:       ", hand_len, ".\n");
  487.               hexmsg = ereg_replace(string:hexstr(hand), pattern:"(..)", replace:"0x\1 ");
  488.               if (!hexmsg) hexmsg = "-- empty --";
  489.               display("debug:   contents:     ", hexmsg, "\n");
  490.             }
  491.  
  492.             # Certificate handshake.
  493.             if (hand_type == 11 && strlen(hand) > 7) {
  494.               # First cert belongs to the server itself.
  495.               cert_len = ord(hand[7])*65536 + ord(hand[8])*256 + ord(hand[9]);
  496.               cert = substr(hand, 10, cert_len+10-1);
  497.               if (debug_level) {
  498.                 display("debug: cert length: ", cert_len, ".\n");
  499.                 hexmsg = ereg_replace(string:hexstr(cert), pattern:"(..)", replace:"0x\1 ");
  500.                 if (!hexmsg) hexmsg = "-- empty --";
  501.                 display("debug: server cert: ", hexmsg, "\n");
  502.               }
  503.               done = 1;
  504.             }
  505.             msg = substr(msg, hand_len+4);
  506.           }
  507.         }
  508.         # Alert message.
  509.         else if (msg_type == 21 && strlen(msg) == 2) {
  510.           alert_lvl = ord(msg[0]);
  511.           alert_desc = ord(msg[1]);
  512.           if (debug_level) {
  513.             display("debug: alert level: ", alert_lvl, "\n");
  514.             display("debug:   desc:      ", alert_desc, "\n");
  515.           }
  516.         }
  517.         # Something else.
  518.         else {
  519.           if (log_verbosity > 1) display("Non-handshake message of type ", msg_type, " received from ", host, ":", port, "!\n");
  520.         }
  521.         if (debug_level) display("debug:\n");
  522.       }
  523.     }
  524.  
  525.     if (done) {
  526.       cert = string(
  527.         "-----BEGIN CERTIFICATE-----\n",
  528.         ereg_replace(
  529.           string:base64(str:cert),
  530.           pattern:"(.{64})", 
  531.           replace:"\1" + raw_string("\n")
  532.         ),
  533.         "\n",
  534.         "-----END CERTIFICATE-----\n"
  535.       );
  536.  
  537.       set_kb_item(name:"SSL/Certificate/" + port, value:cert);
  538.     }
  539.     else {
  540.       # The port was open but we couldn't get the certificate for some reason
  541.       # so let the user know if we're verbosely logging.
  542.       if (log_verbosity > 1) display("Can't get SSL certificate on ", host, ":", port, "!\n");
  543.       return(NULL);
  544.     }
  545.   }
  546.  
  547.   if (encoding =~ "der") {
  548.     local_var der, line;
  549.     der = "";
  550.     foreach line (split(cert, keep:FALSE)) {
  551.       if (line !~ "^-+(BEGIN|END) CERTIFICATE-+$") {
  552.         der += line;
  553.       }
  554.     }
  555.     return(base64_decode(str:der));
  556.   }
  557.   else if (encoding =~ "pem") {
  558.     return(cert);
  559.   }
  560.   else {
  561.     # unsupported encoding.
  562.     return(NULL);
  563.   }
  564. }
  565.